package com.mcv.APNSSupport;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.KeyStore;
import java.util.List;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class SendAPNSMessage {

	private static String staticHost = "gateway.sandbox.push.apple.com";

	/**
	 * @return the passCode
	 */
	public static String getPassCode() {
		return passCode;
	}

	/**
	 * @param passCode
	 *            the passCode to set
	 */
	public static void setPassCode(String passCode) {
		SendAPNSMessage.passCode = passCode;
	}

	/**
	 * @return the apnsReturnCode
	 */
	public static boolean isApnsReturnCode() {
		return apnsReturnCode;
	}

	/**
	 * @param apnsReturnCode
	 *            the apnsReturnCode to set
	 */
	public static void setApnsReturnCode(boolean apnsReturnCode) {
		SendAPNSMessage.apnsReturnCode = apnsReturnCode;
	}

	private static int staticPort = 2195;
	private static String certificateAndKey = "Path/To/Certificates.p12";
	private static String passCode = null;
	private static boolean apnsReturnCode = false;

	public SendAPNSMessage(String certPath, String certPassCode,
			List<APNSDevice> apnsDevice) {
		setCertificateAndKey(certPath + "/Certificates.p12");
		setPassCode(certPassCode);
		for (int i = 0; i < apnsDevice.size(); i++) {
			APNSDevice dev = apnsDevice.get(i);
			if (prepareAPNSPackage(dev.getDeviceToken())) {
				setApnsReturnCode(true);

			}
		}

	}

	public boolean prepareAPNSPackage(String deviceToken) {

		try {

			SSLSocketFactory factory = null;
			try {
				SSLContext ctx;
				KeyManagerFactory kmf;
				KeyStore ks;
				char[] passphrase = "mypassword".toCharArray();

				ctx = SSLContext.getInstance("TLS");
				kmf = KeyManagerFactory.getInstance("SunX509");
				ks = KeyStore.getInstance("PKCS12");

				ks.load(new FileInputStream(certificateAndKey), passphrase);

				kmf.init(ks, passphrase);
				ctx.init(kmf.getKeyManagers(), null, null);

				factory = ctx.getSocketFactory();
			} catch (Exception e) {
				e.printStackTrace();
				throw new IOException(e.getMessage());
			}

			SSLSocket socket = (SSLSocket) factory.createSocket(staticHost,
					staticPort);

			socket.startHandshake();

			sendMessage(socket, deviceToken, getJSONMessage());
			return true;

		} catch (Exception e) {
			e.printStackTrace();
		}

		return false;

	}

	private static String getJSONMessage() {
		String returnString = "";

		String jsonMessage = "{\"aps\":{\"alert\":\"posted a new Image\",\"badge\":0}}";

		returnString = jsonMessage;
		return returnString;
	}

	private static void sendMessage(SSLSocket sock, String deviceToken,
			String msg) throws Exception {
		OutputStream sos = sock.getOutputStream();

		// use a ByteArrayOutputStream so I can see the outputs...
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		DataOutputStream dos = new DataOutputStream(bos);
		dos.writeByte(0); // 1 byte command

		String hexDeviceID = deviceToken.replaceAll(" ", "");

		String[] string = hexDeviceID.replaceAll("([\\da-f]{2})", "$1 ").split(
				" ");

		byte[] binaryDeviceID = new byte[string.length];

		for (int i = 0; i < string.length; i++) {
			binaryDeviceID[i] = (byte) Integer.parseInt(string[i], 16);
		}
		byte[] token = binaryDeviceID;// Hex.decodeHex(tokenHex.replaceAll(" ",
										// "").toCharArray());
		dos.writeShort(token.length); // 2 byte token length
		dos.write(token); // token
		byte[] payload = msg.getBytes("UTF-8");
		dos.writeShort(payload.length); // 2 byte msg length
		dos.write(payload); // payload

		byte[] output = bos.toByteArray();
		// System.out.println("Writing: " + new String(Hex.encodeHex(output)));

		sos.write(output);
		sock.close();
	}

	/**
	 * @return the staticHost
	 */
	public static String getStaticHost() {
		return staticHost;
	}

	/**
	 * @param staticHost
	 *            the staticHost to set
	 */
	public static void setStaticHost(String staticHost) {
		SendAPNSMessage.staticHost = staticHost;
	}

	/**
	 * @return the staticPort
	 */
	public static int getStaticPort() {
		return staticPort;
	}

	/**
	 * @param staticPort
	 *            the staticPort to set
	 */
	public static void setStaticPort(int staticPort) {
		SendAPNSMessage.staticPort = staticPort;
	}

	/**
	 * @return the certificateAndKey
	 */
	public static String getCertificateAndKey() {
		return certificateAndKey;
	}

	/**
	 * @param certificateAndKey
	 *            the certificateAndKey to set
	 */
	public static void setCertificateAndKey(String certificateAndKey) {
		SendAPNSMessage.certificateAndKey = certificateAndKey;
	}

}
